#ifndef HENGINE_H_INCLUDED
#define HENGINE_H_INCLUDED

#include "helper.h"

#include "hScene.h"
#include "hGui.h"
#include "hTrigger.h"
#include "hSound.h"

void functionFromScript(stringc foo, stringc param_table="") {
	if (!foo.size()) return;
	//get function
	lua_getglobal(P.L, foo.c_str());
	// push this table
	if (param_table.size())
		lua_getglobal(P.L, param_table.c_str());
	// use function!
	if(lua_pcall(P.L,1,1,0) != 0)
		printf("error running function : %s", lua_tostring(P.L, -1));

	lua_pop(P.L, 1);
}

class CEventReceiver : public IEventReceiver {
public:
	CEventReceiver(){}
	~CEventReceiver(){}

private:

	bool OnEvent(const SEvent& event) {
		switch (event.EventType) {
		case EET_KEY_INPUT_EVENT:
			switch (event.KeyInput.Key) {
			case KEY_ESCAPE:
				P.Device->closeDevice();
				break;
			default:
				if (event.KeyInput.PressedDown && P.KeyActions[event.KeyInput.Key].size() > 0) {
					stringc param_table;
					//get table name with params
					param_table.append(P.KeyActions[event.KeyInput.Key]).append(stringc(event.KeyInput.Key));
					// use function!
					functionFromScript(P.KeyActions[event.KeyInput.Key], param_table);
				}
				P.KeyState[event.KeyInput.Key] = event.KeyInput.PressedDown;
				break;
			}
		default:
			break;
		}
		return false;
	}
};

CEventReceiver eventReceiver;

/* EngineInit(uint width, uint height) */
int EngineInit(lua_State* l){
	u32 width = 800, height = 600;
	uint n = lua_gettop(l);
	if (n >= 1 && isnum(1)) width = tonum(1);
	if (n == 2 && isnum(2)) height = tonum(2);

	P.Device = createDevice( video::EDT_OPENGL, dimension2du(width, height ), 16, false, false, false, &eventReceiver);
	P.Device->getCursorControl()->setVisible(false);
	P.Init();

	if (!P.Device)
		printf("TODO: Make exception - device creation failed");

	lua_pop(l, 1);

	return 0;
}

int DrawFrame(lua_State*l) {
	if (P.Device->isWindowActive() && P.Device->isWindowFocused()) {
		P.Driver->beginScene(true, true, SColor(255,100,101,140));

		if (P.Scene())
			P.Scene()->drawAll();

		P.GUI->drawAll();

		if(P.Dummy)
			P.Tmgr.checkAll(P.Dummy, P.KeyState[P.UseKey]);

		if (P.EngineActions[EVERY_FRAME].size() > 0)
			functionFromScript(P.EngineActions[EVERY_FRAME], "every_frame_table");

		P.Driver->endScene();
	} else {
		P.Device->yield();
	}
	return 0;
}

/* Run() */
int Run(lua_State* l) {

	uint n = lua_gettop(l);
	if (n >= 1 && isstr(1)) P.EngineActions[EVERY_FRAME] = stringc(tostr(1));
	if (n == 2 && lua_istable(l,2)) lua_setglobal(l, "every_frame_table");

	while(P.Device->run())
		DrawFrame(l);

	return 0;
}

/* SetWindowCaption(string text) */
int SetWindowCaption(lua_State* l) {
	if (!lua_gettop(l) || !isstr(1)) { lua_pop(l, 1); return -1; }
	P.Device->setWindowCaption(stringw(tostr(1)).c_str());

	lua_pop(l, 1);

	return 0;
}

/* AddArchive (string file) */
int AddArchive(lua_State* l) {
	if (!lua_gettop(l) || !isstr(1)) { lua_pop(l, 1); return -1; }
	P.Device->getFileSystem()->addFileArchive(tostr(1));

	lua_pop(l, 1);

	return 0;
}

/* SetKeyAction(int key, string action) */
int SetKeyAction(lua_State* l) {
	int n = lua_gettop(l), key;
	stringc action, param_table;

	if (n >= 1 && isnum(1)) key = tonum(1); else LOG_ERROR("SetKeyAction: first param must be number - key id!\n");
	if (n >= 2 && isstr(2)) action = tostr(2);  else LOG_ERROR("SetKeyAction: second param must be string - foo name!\n");
	if (n == 3)	{
		param_table.append(action).append(stringc(key));
		lua_setglobal(l, param_table.c_str());
	}//  else  LOG_ERROR("SetKeyAction: third param must be table!\n");

	P.KeyActions[key] = action;

	printf("Key: %d set action to \"%s\", param table is \"%s\"\n", key, action.c_str(), param_table.c_str());

	return 0;
}

/* Sleep (uint timeMS) */
int Sleep(lua_State* l) {
	if(lua_gettop(l) && isnum(1))
		P.Device->sleep(tonum(1));
	return 0;
}

void initEngineFuncs() {
	REG(EngineInit);
	REG(SetWindowCaption);
	REG(Run);
	REG(DrawFrame);
   	REG(AddArchive);
   	REG(SetKeyAction);
   	REG(Sleep);

   	initGuiFuncs();
   	initSceneFuncs();
   	initTriggerFuncs();
   	initSoundFuncs();
}

#endif // HENGINE_H_INCLUDED
